﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Sudum
{
    public enum Action { Up, Down, Left, Right, Fire, Jump, Select, Back, Exit };

    public class InputManager
    {
		struct ActionKeys
		{
			public Keys KeyboardKey { get; set; }
			public Buttons GamepadKey { get; set; }
			public Buttons GamepadThumbstick { get; set; }
			public bool ThumbstickMapped { get; set; }
		}

        #region Fields 
        KeyboardState currentKeyboardState;
        KeyboardState oldKeyboardState;
        GamePadState currentGamePadState;
        GamePadState oldGamePadState;
		Dictionary<Action, ActionKeys> mapping = new Dictionary<Action, ActionKeys>();
        #endregion

		#region static members
		public static InputManager Me { get { return inputManager; } }
		static InputManager inputManager = new InputManager();
		#endregion

        #region Constructors and Init Functions

        private InputManager()
        {
            // Assign controls

			// Directions
			Map(Action.Up,		Keys.Up,			Buttons.DPadUp,		Buttons.LeftThumbstickUp);
			Map(Action.Down,	Keys.Down,			Buttons.DPadDown,	Buttons.LeftThumbstickDown);
			Map(Action.Left,	Keys.Left,			Buttons.DPadLeft,	Buttons.LeftThumbstickLeft);
			Map(Action.Right,	Keys.Right,			Buttons.DPadRight,	Buttons.LeftThumbstickRight);

			// Other actions
			Map(Action.Fire,	Keys.Space,			Buttons.A);
			Map(Action.Jump,	Keys.LeftControl,	Buttons.X);
			Map(Action.Select,	Keys.Enter,			Buttons.Start);
			Map(Action.Back,	Keys.Escape,		Buttons.Back);
			Map(Action.Exit,	Keys.Escape,		Buttons.Back);

            currentKeyboardState = oldKeyboardState = Keyboard.GetState();
            currentGamePadState = oldGamePadState = GamePad.GetState(PlayerIndex.One);
        }

		void Map(Action action, Keys key, Buttons gamepadButton)
		{
			ActionKeys actionKeyMap = new ActionKeys();
			actionKeyMap.KeyboardKey = key;
			actionKeyMap.GamepadKey = gamepadButton;
			actionKeyMap.ThumbstickMapped = false;
			mapping.Add(action, actionKeyMap);
		}

		void Map(Action action, Keys key, Buttons gamepadButton, Buttons thumbstickDirection)
		{
			ActionKeys actionKeyMap = new ActionKeys();
			actionKeyMap.KeyboardKey = key;
			actionKeyMap.GamepadKey = gamepadButton;
			actionKeyMap.GamepadThumbstick = thumbstickDirection;
			actionKeyMap.ThumbstickMapped = true;
			mapping.Add(action, actionKeyMap);
		}

        #endregion

        #region Keyboard Stuff

        private bool KbPressed(Keys key)
        {
            return oldKeyboardState.IsKeyUp(key) && currentKeyboardState.IsKeyDown(key);
        }

        private bool KbReleased(Keys key)
        {
            return oldKeyboardState.IsKeyDown(key) && currentKeyboardState.IsKeyUp(key);
        } 

        #endregion

        #region Gamepad stuff

        private bool PadPressed(Buttons button)
        {
            if (!currentGamePadState.IsConnected)
				return false;
            return oldGamePadState.IsButtonUp(button) && currentGamePadState.IsButtonDown(button);
        }

        private bool PadReleased(Buttons button)
        {
			if (!currentGamePadState.IsConnected)
				return false;
			return oldGamePadState.IsButtonDown(button) && currentGamePadState.IsButtonUp(button);
        }

        #endregion

        #region Methods

        //insert after checking for controls

        public void Update()
        {
            oldGamePadState = currentGamePadState;
            oldKeyboardState = currentKeyboardState;
            currentGamePadState = GamePad.GetState(PlayerIndex.One);
            currentKeyboardState = Keyboard.GetState();
        }

        public bool Pressed(Action action)
        {
			ActionKeys actionKeys = mapping[action];
			bool pressed = KbPressed(actionKeys.KeyboardKey);
			pressed |= PadPressed(actionKeys.GamepadKey);
			if (actionKeys.ThumbstickMapped)
				pressed |= PadPressed(actionKeys.GamepadThumbstick);
			return pressed;
        }

		public bool Released(Action action)
        {
			ActionKeys actionKeys = mapping[action];
			bool released = KbReleased(actionKeys.KeyboardKey);
			released |= PadReleased(actionKeys.GamepadKey);
			if (actionKeys.ThumbstickMapped)
				released |= PadReleased(actionKeys.GamepadThumbstick);
			return released;
        }

		public bool IsDown(Action action)
        {
			ActionKeys actionKeys = mapping[action];
			bool isDown = currentKeyboardState.IsKeyDown(actionKeys.KeyboardKey);

			if (currentGamePadState.IsConnected)
			{
				isDown |= currentGamePadState.IsButtonDown(actionKeys.GamepadKey);
				if (actionKeys.ThumbstickMapped)
					isDown |= currentGamePadState.IsButtonDown(actionKeys.GamepadThumbstick);
			}
			return isDown;
        }

		public bool IsUp(Action action)
        {
			ActionKeys actionKeys = mapping[action];
			bool isUp = currentKeyboardState.IsKeyUp(actionKeys.KeyboardKey);

			if (currentGamePadState.IsConnected)
			{
				isUp |= currentGamePadState.IsButtonUp(actionKeys.GamepadKey);
				if (actionKeys.ThumbstickMapped)
					isUp |= currentGamePadState.IsButtonUp(actionKeys.GamepadThumbstick);
			}
			return isUp;
        }
        #endregion
    }
}
